#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/ptrace.h>
#include <linux/kernel.h>

// kprobe 预处理函数
static int my_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
    // regs->di、regs->si 等可以访问函数参数（具体参数位置因架构而异）
    printk(KERN_INFO "Kprobe hit at %lx, argument1: %ld, argument2: %ld\n",
           regs->ip, regs->di, regs->si); // regs->di 是第一个参数，regs->si 是第二个参数
	
	const char __user *user_filename = (const char __user *)regs->si;
    char *kern_filename = NULL;

	int len = strnlen_user(user_filename, 256);
    if (len >= 256) {
        return 0;
    }

    /* 分配内核空间并复制文件名 */
    kern_filename = kmalloc(len + 1, GFP_KERNEL);
    if (!kern_filename) {
        return 0;
    }

    if (copy_from_user(kern_filename, user_filename, len)) {
        kfree(kern_filename);
        return 0;
    }
    kern_filename[len] = '\0';

    printk(KERN_INFO "Kprobe: open file %s\n", kern_filename);

    return 0;
}

// kprobe 后处理函数
static void my_post_handler(struct kprobe *p, struct pt_regs *regs, unsigned long flags)
{
    printk(KERN_INFO "Kprobe post at %lx\n", regs->ip);
}

// kretprobe 返回处理函数
static int rp_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
    long ret = regs_return_value(regs); // 获取函数返回值
    printk(KERN_INFO "Kretprobe hit, return value: %ld\n", ret);

    return 0;
}

// 定义一个 kprobe，用于探测内核函数 do_sys_openat2
static struct kprobe kp = {
    .symbol_name = "do_sys_openat2", // 目标函数名
    .pre_handler = my_pre_handler,
    .post_handler = my_post_handler,
};

// 定义一个 kretprobe，用于探测内核函数 do_sys_openat2 的返回
static struct kretprobe rp = {
    .kp.symbol_name = "do_sys_openat2", // 目标函数名
    .handler = rp_handler,
    .maxactive = 10, // 预分配的返回探针实例数量
};

// 模块初始化函数
static int __init my_kprobes_init(void)
{
    int ret;

    // 注册 kprobe
    ret = register_kprobe(&kp);
    if (ret < 0) {
        printk(KERN_ERR "Register kprobe failed\n");
        return ret;
    }

    // 注册 kretprobe
    ret = register_kretprobe(&rp);
    if (ret < 0) {
        unregister_kprobe(&kp); // 注册 kretprobe 失败时注销 kprobe
        printk(KERN_ERR "Register kretprobe failed\n");
        return ret;
    }

    printk(KERN_INFO "Kprobes registered successfully\n");

    return 0;
}

// 模块退出函数
static void __exit my_kprobes_exit(void)
{
    unregister_kprobe(&kp); // 注销 kprobe
    unregister_kretprobe(&rp); // 注销 kretprobe
    printk(KERN_INFO "Kprobes unregistered\n");
}

module_init(my_kprobes_init);
module_exit(my_kprobes_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A Kprobes example");
